package com.snail.starter.redis.holder;

import com.snail.starter.redis.enums.IRedisKey;
import org.springframework.data.geo.Circle;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.lang.Nullable;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.Set;

/**
 * @author: snail framework
 * @Date: 2023/3/3 下午1:56
 * @Version: 1.0.0
 */
public class RedisHolder {

    @Resource
    RedisTemplate<String, Object> redisTemplate;

    /**
     * 设置key
     *
     * @param iRedisKey key前缀
     * @param bizKey    业务key
     */
    public void set(IRedisKey iRedisKey, String bizKey) {
        redisTemplate.opsForValue().set(iRedisKey.getPreFixKey() + bizKey, iRedisKey.getDefaultValue(), iRedisKey.getTtl(), iRedisKey.getTimeUnit());
    }

    /**
     * 设置key
     *
     * @param iRedisKey key前缀
     * @param bizKey    业务key
     * @param value     业务value
     */
    public void set(IRedisKey iRedisKey, String bizKey, Object value) {
        redisTemplate.opsForValue().set(iRedisKey.getPreFixKey() + bizKey, null == value ? iRedisKey.getDefaultValue() : value, iRedisKey.getTtl(), iRedisKey.getTimeUnit());
    }

    public Object getValue(IRedisKey iRedisKey, String bizKey) {
        redisTemplate.expire(iRedisKey.getPreFixKey() + bizKey, iRedisKey.getTtl(), iRedisKey.getTimeUnit());
        return redisTemplate.opsForValue().get(iRedisKey.getPreFixKey() + bizKey);
    }

    /**
     * 设置key
     *
     * @param iRedisKey key前缀
     * @param bizKey    业务key
     */
    public void delete(IRedisKey iRedisKey, String bizKey) {
        redisTemplate.delete(iRedisKey.getPreFixKey() + bizKey);
    }

    /**
     * key 存在时,则设置值
     *
     * @param iRedisKey key前缀
     * @param bizKey    业务key
     * @param value     业务value
     */
    public boolean setIfPresent(IRedisKey iRedisKey, String bizKey, Object value) {
        Boolean flag = redisTemplate.opsForValue().setIfPresent(iRedisKey.getPreFixKey() + bizKey, null == value ? iRedisKey.getDefaultValue() : value, iRedisKey.getTtl(), iRedisKey.getTimeUnit());
        return null == flag ? Boolean.FALSE : flag;
    }

    /**
     * key 不存在时，则设置值
     *
     * @param iRedisKey key前缀
     * @param bizKey    业务key
     * @param value     业务value
     */
    public boolean setIfAbsent(IRedisKey iRedisKey, String bizKey, Object value) {
        Boolean flag = redisTemplate.opsForValue().setIfAbsent(iRedisKey.getPreFixKey() + bizKey, null == value ? iRedisKey.getDefaultValue() : value, iRedisKey.getTtl(), iRedisKey.getTimeUnit());
        return null == flag ? Boolean.FALSE : flag;
    }

    /**
     * 尝试获取锁
     *
     * @param iRedisKey key前缀
     * @param bizKey    业务key
     */
    public boolean tryLock(IRedisKey iRedisKey, String bizKey) {
        return setIfAbsent(iRedisKey, bizKey, 1);
    }

    /**
     * 锁续约
     *
     * @param iRedisKey key前缀
     * @param bizKey    业务key
     */
    public boolean lockRenewal(IRedisKey iRedisKey, String bizKey) {
        Boolean flag = redisTemplate.opsForValue().setIfPresent(iRedisKey.getLockPrefix() + bizKey, 1, iRedisKey.getTtl(), iRedisKey.getTimeUnit());
        if (null != flag && flag) {
            return true;
        }
        return tryLock(iRedisKey, bizKey);
    }

    /**
     * 解锁
     *
     * @param iRedisKey key前缀
     * @param bizKey    业务key
     */
    public boolean unLock(IRedisKey iRedisKey, String bizKey) {
        Boolean flag = redisTemplate.delete(bizKey);
        return null == flag ? Boolean.FALSE : flag;
    }

    /**
     * 设置Set 类型
     * @param iRedisKey key前缀
     * @param bizKey 业务key
     * @param values list 值
     */
    public void setSet(IRedisKey iRedisKey, String bizKey, List<Object> values) {
        redisTemplate.opsForSet().add(iRedisKey.getPreFixKey() + bizKey, values);
        redisTemplate.expire(iRedisKey.getPreFixKey() + bizKey, iRedisKey.getTtl(), iRedisKey.getTimeUnit());
    }
    /**
     * 设置Set 类型
     * @param iRedisKey key前缀
     * @param bizKey 业务key
     * @param value list 值
     */
    public void setSet(IRedisKey iRedisKey, String bizKey, Object value) {
        redisTemplate.opsForSet().add(iRedisKey.getPreFixKey() + bizKey, value);
        redisTemplate.expire(iRedisKey.getPreFixKey() + bizKey, iRedisKey.getTtl(), iRedisKey.getTimeUnit());
    }

    /**
     * 删除set元素
     * @param iRedisKey key前缀
     * @param bizKey 业务key
     */
    public Object popSet(IRedisKey iRedisKey, String bizKey) {
        Object value =  redisTemplate.opsForSet().pop(iRedisKey.getPreFixKey() + bizKey);
        redisTemplate.expire(iRedisKey.getPreFixKey() + bizKey, iRedisKey.getTtl(), iRedisKey.getTimeUnit());
        return value;
    }

    /**
     * 删除set元素
     * @param iRedisKey key前缀
     * @param bizKey 业务key
     */
    public void removeSet(IRedisKey iRedisKey, String bizKey,String obj) {
       redisTemplate.opsForSet().remove(iRedisKey + bizKey, obj);
       redisTemplate.expire(iRedisKey.getPreFixKey() + bizKey, iRedisKey.getTtl(), iRedisKey.getTimeUnit());
    }

    /**
     * 获取set key对应的size
     * @param iRedisKey key前缀
     * @param bizKey 业务key
     * @return set 的size
     */
    public long getSetSize(IRedisKey iRedisKey, String bizKey) {
        Long size = redisTemplate.opsForSet().size(iRedisKey.getPreFixKey() + bizKey);
        if(null == size){
            return 0L;
        }
        return size;
    }

    /**
     * 获取所有set的值
     * @param iRedisKey key前缀
     * @param bizKey 业务key
     * @return set的值
     */
    public Set<Object> getSetValues(IRedisKey iRedisKey, String bizKey) {
        Set<Object> members = redisTemplate.opsForSet().members(iRedisKey.getPreFixKey() + bizKey);
        if(null == members || members.isEmpty()){
            return Collections.emptySet();
        }
        return members;
    }

    /**
     *  是否含有key
     * @param iRedisKey key前缀
     * @param bizKey 业务key
     * @return
     */
    public boolean hasKey(IRedisKey iRedisKey, String bizKey){
        return redisTemplate.hasKey(iRedisKey.getPreFixKey() + bizKey);
    }

    /**
     * geo添加
     *
     * @param iRedisKey key前缀
     * @param bizKey    业务key
     * @param point     经纬度信息
     * @param member    成员
     * @return {@link Long}
     */
    @Nullable
    public Long geoAdd(IRedisKey iRedisKey, String bizKey, Point point, String member) {
        long result = redisTemplate.opsForGeo().add(iRedisKey.getPreFixKey() + bizKey, point, member);
        if(iRedisKey.getTtl() > 0) {
            redisTemplate.expire(iRedisKey.getPreFixKey() + bizKey, iRedisKey.getTtl(), iRedisKey.getTimeUnit());
        }
        return result;
    }

    /**
     * 查询半径内成员
     *
     * @param iRedisKey key前缀
     * @param bizKey    业务key
     * @param within    范围
     * @param args      参数
     * @return {@link GeoResults}<{@link RedisGeoCommands.GeoLocation}<{@link Object}>>
     */
    public GeoResults<RedisGeoCommands.GeoLocation<Object>> geoRadius(IRedisKey iRedisKey, String bizKey, Circle within, RedisGeoCommands.GeoRadiusCommandArgs args) {
        return redisTemplate.opsForGeo().radius(iRedisKey.getPreFixKey() + bizKey, within, args);
    }

    /**
     * 删除
     *
     * @param iRedisKey key前缀
     * @param bizKey    业务key
     * @param member    成员
     * @return {@link Long}
     */
    @Nullable
    public Long geoRemove(IRedisKey iRedisKey, String bizKey, String member) {
        return redisTemplate.opsForGeo().remove(iRedisKey.getPreFixKey() + bizKey, member);
    }

    public Long increment(IRedisKey iRedisKey, String bizKey, long delta){
        return redisTemplate.opsForValue().increment(iRedisKey.getPreFixKey() + bizKey, delta);
    }
}